home *** CD-ROM | disk | FTP | other *** search
/ BBS Toolkit / BBS Toolkit.iso / rbbs_pc / msgtos20.zip / SPAZ_150.LZH / SPAZ.ASM next >
Assembly Source File  |  1990-10-07  |  67KB  |  2,044 lines

  1. ;---------------------------------------------------------------------;
  2. ;                                                                     ; 
  3. ;                               SPAZ 1.50                             ; 
  4. ;                            October 7, 1990                          ; 
  5. ;                                                                     ; 
  6. ;           By Dan Thomson, Andrew Farmer and Jeffrey Nonken.         ;
  7. ;                                                                     ; 
  8. ;                                                                     ; 
  9. ;                              SOURCE CODE                            ; 
  10. ;                                                                     ; 
  11. ;                                                                     ; 
  12. ;         Copyright (c) 1989-1990 Dan Thomson and Andrew Farmer.      ; 
  13. ;                         All Rights Reserved.                        ; 
  14. ;                                                                     ; 
  15. ;---------------------------------------------------------------------;
  16.  
  17. name    SPAZ
  18. page    60,132
  19. title    Smart Pak, Arc and Zoo Shell
  20.  
  21. false    equ    00h
  22. tab    equ    09h                ;ASCII tab
  23. lf    equ    0ah                ;ASCII line feed
  24. cr    equ    0dh                ;ASCII carriage return
  25. blank    equ    20h                ;ASCII blank
  26. arc_len    equ    21h                ;Only save info for sort
  27. DOS    equ    21h                ;DOS int call
  28. CntrolC    equ    23h                ;Control C checking...
  29. cmdtail    equ    80h                ;Offset to command tail
  30. true    equ    255
  31. bsize    equ    4096                ;Size of copy buffer
  32.  
  33. ; If you have lots of memory, (Not running a multi-tasker) then the
  34. ; following variables can be changed to allow running SPAZ a little
  35. ; faster, but using alot more memory....
  36.  
  37. ; 1. Entries is the number of members in a standard ARC file that
  38. ;    can be stored for sorting. If an ARC has more than 150, the
  39. ;    file is not sorted. This can be increased until buffers reach
  40. ;    (64K - code size). Each entry needs 29 bytes of buffer space.
  41.  
  42. Entries        equ    150
  43.  
  44. ; 2. This entry controls how many file names will be stored in
  45. ;    memory. This is used during wild card processing to run
  46. ;    SPAZ on each individual name. It has been set at 30 to
  47. ;    allow most systems to run without writing to disk. If you
  48. ;    run a busy mail system or process alot of archives, this
  49. ;    can be increased (at the cost of memory) for faster processing.
  50.  
  51. NamesFound    equ    30
  52.  
  53. ;DOS interupt equates...
  54.  
  55. CharacterOutput        equ    02h
  56. OutputString        equ    09h
  57. SetDTA            equ    1ah
  58. SetVector        equ    25h
  59. GetVector        equ    35h
  60. CreateFile        equ    3ch
  61. OpenFile        equ    3dh
  62. CloseFile        equ    3eh
  63. ReadFile        equ    3fh
  64. WriteFile        equ    40h
  65. DeleteFile        equ    41h
  66. MoveFilePointer        equ    42h
  67. GetOrSetAttribute    equ    43h
  68. ModifyMemory        equ    4ah
  69. ExecuteProgram        equ    4bh
  70. ExitWithCode        equ    4ch
  71. GetReturnCode        equ    4dh
  72. SearchForFirst        equ    4eh
  73. SearchForNext        equ    4fh
  74. RenameFile        equ    56h
  75.  
  76. cseg    segment    para public 'code'
  77.     assume    cs:cseg,ds:cseg,es:cseg,ss:cseg
  78.  
  79.     org    100h                ;Skip to end of the PSP
  80. entry:    jmp    start                ;comm file entry always 0100H
  81.  
  82. TitleScreen    db    cr,lf,'SPAZ 1.50; Written by Dan Thomson, Andrew Farmer and Jeffrey Nonken.',cr,lf
  83.         db          'Copyright (c) 1989-1990 Dan Thomson & Andrew Farmer.  All Rights Reserved.',cr,lf
  84. TitleLength    equ    $-TitleScreen
  85.  
  86. Usage    db    cr,lf,'Syntax/Usage: SPAZ [switches] Path\Archive [switches] [files....]'
  87.     db    cr,lf,'Square brackets indicate optionals. Switches are set with - or /.'
  88.     db    cr,lf,cr,lf,'Switches:',cr,lf,cr,lf
  89.     db    '  -A       Will use ONLY "ARCE" on standard (ARC Style) archives.',cr,lf
  90.     db    '  -D       Will delete the archive if the extract was successful.',cr,lf
  91.     db    '  -F       Will process all Compressed Mail bundles found in Dir.',cr,lf
  92.         db      '  -Maddr   Will calculate Compressed Mail bundle name to show the',cr,lf
  93.         db      '           sending Net Address.  "addr" is YOUR Net/Node address.',cr,lf
  94.     db    '  -N       Will NOT attempt to sort the archive prior to extract.',cr,lf
  95.     db    '  -O|-R    Overwrite.  Will NOT prompt if existing file is found.',cr,lf
  96.     db    '  -V       Verbose Mode.  Will display the runtime configuration.',cr,lf,cr,lf
  97.     db    'If -F is used then "Archive" MUST be a Path ONLY, not a Filename.',cr,lf
  98.         db      'Use of -F forces -D and -O to be set TRUE and -N to be set False.',cr,lf
  99. UsageLength    equ    $-Usage
  100.  
  101.     even
  102. errmsg    dw    err2,err2,err2,err4,err5,err13
  103.     dw    err13,err8,err8,err10,err11,err5
  104.     dw    err13,err15,err15,err2,err2,err2
  105.     dw    err20,err20,err21,err22,err23,err24,err25
  106.  
  107. err2    db    cr,lf,'File not found: ',0
  108. err4    db    cr,lf,'Too many open files.',cr,lf,0
  109. err5    db    cr,lf,'Access denied.',cr,lf,0
  110. err8    db    cr,lf,'Insufficient memory.',cr,lf,0
  111. err10    db    cr,lf,'Invalid environment.',cr,lf,0
  112. err11    db    cr,lf,'Invalid format.',cr,lf,0
  113. err13    db    cr,lf,'Invalid data.',cr,lf,0
  114. err15    db    cr,lf,'Invalid drive was specified.',cr,lf,0
  115. err20    db    cr,lf,'Invalid file format, not changed.',cr,lf,0
  116. err21    db    cr,lf,'Too many archive entries.',cr,lf,0
  117. err22    db    cr,lf,'Unarchiver not found on path.',cr,lf,0
  118. err23    db    cr,lf,'Invalid Command Line Option used.',cr,lf,0
  119. err24    db    cr,lf,'Archive name not specified!',cr,lf,0
  120. err25    db    cr,lf,'Invalid directory specified.',cr,lf,'$'
  121. NoMail    db    cr,lf,'No Compressed Mail Bundles Found in Directory!',cr,lf,cr,lf,'$'
  122. SortErr    db    'Sort failed, attempting extract anyway...',cr,lf,0
  123. zerr    db    'Problem reading archive for type check.',cr,lf,0
  124. crlf    equ    $-3
  125. TempErr    db    'Unable to process temporary file, aborting.',cr,lf,'$'
  126. del_msg    db    cr,lf,'Extract successful - Unlinking ',0
  127. will    db    cr,lf,'Will ',0
  128. wont    db    cr,lf,'Will NOT ',0
  129. info1    db    'use ARCE on standard (ARC style) archives.',0
  130. info2    db    'delete the archives if extract was successful.',0
  131. info3    db    'attempt to sort the archives.',cr,lf,0
  132. info4    db    ' - From: ',0
  133. info5    db    'expand network addresses.',0
  134. info6    db    'process Compressed Mail bundles ONLY.',0
  135. info7    db    'operate in overwrite mode.',0
  136.  
  137. msg1    db    ' Adjusting: ',0
  138. msg2    db    '- Location = ',0
  139. msg3    db    '   Length = ',0
  140. msg4    db    'Searching: ',0
  141.  
  142. UnArc1    db    'PKXARC.EXE',0
  143. UnArc2    db    'PKXARC.COM',0
  144. UnArc3    db    'PKUNPAK.EXE',0
  145. UnArc4    db    'LOOZ.EXE',0
  146. UnArc5    db    'PAK.EXE',0
  147. UnArc6    db    'ARCE.COM',0
  148. UnArc7    db    'ZOO.EXE',0
  149. UnArc8    db    'DWC.EXE',0
  150. UnArc9    db    'PKUNZIP.EXE',0
  151. UnArc10    db    'LHARC.EXE',0
  152.  
  153. on_disk        db    0            ;True if names on disk    .jjn
  154. num_names    db    0            ;# of filenames in buffer .jjn
  155. num_hdr        db    0            ;Number of headers input
  156. first        db    true            ;Flag for search first/next
  157. flag        db    false            ;Show sort done on pass
  158. Zooflag        db    false            ;Flag to signify zoo file
  159. Crushed        db    false            ;Flag to signify crushed files
  160. A_Flag        db    false            ;Set no default archiver
  161. D_Flag        db    false            ;Set no delete when finished
  162. F_Flag        db    false            ;Set no mail only stuff
  163. M_Flag        db    false            ;Show net/node on extract?
  164. N_Flag        db    true            ;Set default sort performed
  165. O_Flag        db    false            ;Set default to non-overwrite
  166. Q_Flag        db    true            ;Set default to quiet
  167. IsZip        db    false            ;Flag to show ZIP file
  168. IsDWC        db    false            ;Flag to show DWC file
  169. IsLZH        db    false            ;Flag to show LZH file
  170. Parsed        db    false            ;Flag to show names were parsed
  171. Got_name    db    false            ;Cmd line fname is OK...
  172. Characters    db    false            ;Print string char counter
  173. Last_Chance    db    false            ;Flag for Arce useage
  174. elevel        db    0            ;Last reported error level
  175. count        db    0            ;Number of passes complete
  176. order        db    0            ;Flag to show archive in order
  177. temp        db    'SpazTmp1.$$$',0    ;Temp filename to use
  178. thomlen    equ    $-temp                ;                          .jjn
  179. filename_file    db    'SpazTmp2.$$$',0    ;Filename for list of files
  180. end_arc        db    1Ah,0            ;Mark to show end of arc
  181.     even
  182. arg_len        dw    0            ;Length of command line arg
  183. buf_pos        dw    0            ;Position in header buffer
  184. endpath        dw    0            ;Holds end of path address
  185. pathlen        dw    0            ;Holds length of path      .jjn
  186. files_handle    dw    0            ;Handle for filespec file  .jjn
  187. name_count    dw    0            ;Number of filenames found .jjn
  188. names_used    dw    0            ;Number of names used after.jjn
  189.                         ; all the names were found .jjn
  190. fname_ptr    dw    0            ;Point into filename buffer.jjn
  191. Opt_Address    dw    false            ;Pointer to cmd line fname
  192. Opt_Length    dw    false            ;Address of cmd line fname
  193. high_pos    dw    0            ;High byte of file pointer
  194. low_pos        dw    0            ;Low byte of file pointer
  195. in_handle    dw    0            ;Handle for read file
  196. out_handle    dw    0            ;Handle for write file
  197.  
  198.  
  199. par_blk    dw    0                ;Copy of parent's environment
  200.     dw    offset cmd_cnt            ;Pointer to command line
  201. sg1    dw    0
  202.     dw    offset    fcb1
  203. sg2    dw    0
  204.     dw    offset     fcb2
  205. sg3    dw    0
  206.  
  207. stk_seg        dw    0            ;Saved stack segment
  208. stk_ptr        dw    0            ;Saved stack pointer
  209. dir        dw    0            ;Pointer for PATH search
  210. enddir        dw    0            ;End address of PATH variable
  211. cmd1_cnt    dw    0            ;Length of wildcard filename
  212. env_len        dw    0            ;Length of PATH in Environment
  213. BundlePosition    dw    offset BundleNames    ;Current position for mail
  214. env        db    'PATH',0        ;Environment variable to find
  215. DefaultBundle    db    '*.MO?',0        ;First mail type to look for
  216. BundleNames    db    'TUWETHFRSASU'        ; and the rest of 'em....
  217.  
  218.  
  219. Spaz    proc    near                ;Entry point from MS-DOS
  220.  
  221. start:  mov    AX,CS
  222.     mov    sg1,AX
  223.     mov    sg2,AX
  224.     mov    sg3,AX
  225.  
  226.     mov    AH,SetDTA            ;AH = Set Disk Tranfer Area
  227.     mov    DX,offset dta_buf        ;Address of scratch space
  228.     int    DOS                ;Give it to DOS
  229.  
  230.     xor    AX,AX
  231.     mov    word ptr Names_Count,AX
  232.     cli                    ;Disable interupts
  233.     lea    sp,bottom-1            ;Move stack to save position
  234.     sti                    ;OK for interups now...
  235.  
  236.      mov    DX,offset bottom        ;Point DX to end of Spaz
  237.     mov    BX,DX                ;Info needed in BX
  238.     add    BX,0fh                ;Add 1 paragraph to it
  239.     mov    CL,4                ;CL = counter for shift
  240.     shr    BX,CL                ;= BX/16 (# of paras needed)
  241.     mov    AH,ModifyMemory            ;AH = Modify memory block
  242.     int    DOS                ;Extra memory released...
  243.  
  244. ; First, identify self and examine parameters...
  245.  
  246.     mov    DX,offset TitleScreen        ;DX points to message
  247.     mov    BX,2                ;Output to standard error
  248.     mov    CX,TitleLength            ;Length of header string
  249.     mov    AH,WriteFile            ;Output to handle
  250.     int    DOS                ;Call DOS to do it
  251.     mov    SI,offset env            ;Search for 'PATH'
  252.     mov    es,es:[2ch]            ;Get environment segment
  253.     call    getenv                ;Read in PATH string
  254.  
  255.     mov    BX,cmdtail            ;ES:BX = command parameters
  256.     call    argc                ;Get number of arguments
  257.     cmp    AX,2                ;At least 1 argument?
  258.     jae    args_ok                ;If yes, keep going
  259.  
  260. Syntax:    mov    DX,offset Usage            ;DX points to usage string
  261.     mov    BX,2                ;Output to standard error
  262.     mov    CX,UsageLength            ;Length of usage string
  263.     mov    AH,WriteFile            ;Output to handle
  264.     int    DOS                ;Call DOS to do it
  265.     mov    AL,0                ;Errorlevel 0 exit
  266.     mov    AH,ExitWithCode            ;AH = Terminate to DOS
  267.     int    DOS                ;Transfer to DOS (for good)
  268.  
  269. args_ok:
  270.     call    options                ;Scan off any options
  271.  
  272. ; Here, ES:BX = argument address and AX = argument length
  273.  
  274.     cld                    ;Direction register increments
  275.     mov    SI,BX                ;Point SI to argument
  276.     lea    DI,cmd1                ;DI = destination
  277.     mov    CX,AX                ;Put character count in CX
  278.     mov    cmd1_cnt,AX            ;And save it for later!
  279.     rep movsb                ;Move argument to buffer
  280.  
  281. ; End the filename (or PATH if -F used) with a zip.
  282.  
  283.     mov    byte ptr [DI],0
  284.  
  285. ; Here, we check for a -F option. If it is true, we tack on the
  286. ; default filename (*.MO?) and start a mail run.
  287.  
  288.     cmp    F_Flag,true            ;Is this a mail run?
  289.     jne    NotAMailRun            ;Nope, continue
  290.  
  291.     cmp    byte ptr [DI-1],'\'        ;Did they have backslash?
  292.     je    AddName                ;If yes, do the name
  293.     mov    byte ptr [DI],'\'        ;Else add a slash
  294.     inc    word ptr cmd1_cnt        ;And bump counter
  295.     inc    DI                ;Adjust pointer
  296. AddName:
  297.     mov    byte ptr [DI-1],0        ;Make it ASCIIZ
  298.     mov    DX,offset cmd1            ;Point to filename/path
  299.     mov    AX,4300h            ;Get attribute
  300.     int    DOS                ;Call DOS to do it
  301.     mov    byte ptr [DI-1],'\'        ;Restore back slash
  302.     and    CX,00010000b            ;Is this a directory?
  303.     jnz    DirectoryFound            ;Go if yes.
  304.     mov    DX,offset err25            ;Invalid directory message
  305.     mov    AH,OutputString            ;DOS print string function
  306.     int    DOS                ;Call DOS to do it
  307.     jmp    syntax                ;Display syntax screen
  308.  
  309. DirectoryFound:
  310.     mov    SI,offset DefaultBundle        ;Point to bundle name
  311.     mov    CX,3                ;Count for name length
  312.     rep    movsw                ;Stuff name in buffer
  313.     add    cmd1_cnt,6            ;Fix the counter
  314.     jmp    short Isolate            ;No need to check it now
  315.  
  316. ; Here, we will check to make sure there is a valid extension.
  317. ; If none was given, a default extention of '.*' will be added.
  318.  
  319. NotAMailRun:
  320.     std                    ;Set up to move backwards
  321.     mov    SI,offset cmd1            ;Get address of filename
  322.     mov    DI,SI                ;So we can check for end
  323.     mov    AX,cmd1_cnt            ;Get length in AX
  324.     add    SI,AX                ;Point to end of filename
  325.     push    SI                ;Save end address
  326. scan:    lodsb                    ;Get a character
  327.     cmp    AL,'.'                ;Is it a period?
  328.     je    ExtentionIsOk            ;If yes, extention OK
  329.     cmp    AL,'\'                ;Is it filename separater?
  330.     je    UseDefault            ;Stop if yes
  331.     cmp    DI,SI                ;Scanned whole name?
  332.     jne    scan                ;No, go get more
  333. UseDefault:
  334.     pop    DI                ;DI = end address of filename
  335.     mov    byte ptr [DI],'*'        ;Add full wildcard search
  336.     mov    byte ptr [DI+1],'.'        ;Add a dot to filename
  337.     mov    byte ptr [DI+2],'*'        ;Add wildcard extension
  338.     mov    byte ptr [DI+3],0        ;End it with a zip
  339.     add    word ptr cmd1_cnt,3        ;Adjust length count
  340.     push    DI                ;Maintain stack balance
  341.  
  342. ; Next, we isolate the path from the filename so that successive
  343. ; filenames can be tacked onto it in case wildcards are used...
  344.  
  345.     public    ExtentionIsOk
  346. ExtentionIsOk:
  347.     add    SP,2                ;Remove garbage from stack
  348.  
  349. Isolate:
  350.     call    show_opt            ;Display option info
  351.     std                    ;Set up to move backwards
  352.     mov    SI,offset cmd1            ;Get address of filename
  353.                         ;so we can check for a path.jjn
  354.     mov    CX,cmd1_cnt            ;Get length in CX          .jjn
  355.     add    SI,CX                ;SI = end of filename      .jjn
  356.     dec    SI                ;                          .jjn
  357.     public    path1
  358. path1:    lodsb                    ;Get a character
  359.     cmp    AL,'\'                ;Filename separator?
  360.     je    save_path            ;Stop if yes
  361.     cmp    AL,':'                ;Drive separator?
  362.     je    save_path            ;Stop if yes
  363.     loop    path1                ;Decrement and loop        .jjn
  364.     inc    SI
  365.     mov    endpath,SI            ;Save address
  366.     mov    pathlen,CX            ;Save path length (0)      .jjn
  367.     jmp    short _end_p            ;Skip double save          .jjn
  368.     public    save_path
  369. save_path:
  370.     inc    SI                ;Adjust past \ character
  371.     inc    SI                ;Need 2 for auto dec...
  372.     mov    endpath,SI            ;Save address of end of path
  373.     mov    pathlen,CX            ;Save path length          .jjn
  374. _end_p:                        ;                          .jjn
  375.     cld                    ;Set direction forward
  376. ;
  377. ; Now we call the wildcard expander. This creates a list of filenames that
  378. ; match the filespec so we can retrieve them later. If there are more than
  379. ; 'NamesFound' matches, it will save them on disk.
  380. ;
  381.     mov    on_disk,0            ;List of files is not on disk
  382.     mov    Name_count,0            ;No names found yet
  383.     mov    num_names,0
  384. DoAllMail:
  385.     call    FindNames            ; Find all matching files  .jjn
  386.     cmp    F_Flag,true            ;Are we doing a mail run?
  387.     jne    NotDoingMail            ;Go if not
  388.  
  389.     mov    SI,BundlePosition        ;Get address for bundle name
  390.     cmp    SI,offset SPAZ            ;No more names to do?
  391.     je    NotDoingMail            ;If not, we're done...
  392.     lodsw                    ;Get next bundle name
  393.     mov    DI,EndPath            ;End of path to filename
  394.     add    DI,2                ;Adjust to right spot
  395.     stosw                    ;And stuff in new name
  396.     mov    BundlePosition,SI        ;Save new name offset
  397.     jmp    short DoAllMail            ;And get more filenames
  398.  
  399. NotDoingMail:
  400.     cmp    on_disk,0            ;Is stuff on disk?
  401.     jz    NothingOnDisk            ;Nope skip pointer adjust
  402.     mov    AH,MoveFilePointer        ;Move pointer DOS function
  403.     xor    CX,CX                ;Offset from beginning of file
  404.     mov    DX,CX                ;32 bit
  405.     mov    AL,CL                ;Mark for 'beginning'
  406.     mov    BX,files_handle            ;Get the file handle
  407.     int    DOS                ;Call DOS to do it
  408. NothingOnDisk:
  409.     mov    AX,name_count            ; number of names found
  410.     or    AX,AX                ; return with zero flag set
  411.     jnz    Main                ; skip error stuff         .jjn
  412.  
  413. ; If we got here, there were no names found.
  414. ; (Moved from the old wild_card procedure. .jjn)
  415.  
  416.     cmp    F_Flag,true            ;Was this a mail run?
  417.     jne    NormalNotFound            ;If not, do normal exit
  418.     mov    DX,offset NoMail        ;Mail run error message
  419.     mov    AH,OutputString            ;DOS print string function
  420.     int    DOS                ;Call DOS to do it
  421.     jmp    short DoneTotally        ;Denis Miller time
  422. NormalNotFound:
  423.     mov    AX,2                ;Change error to file not found
  424.     call    err_msg                ;Display error in english
  425.     push    AX                ;Save error code
  426.     mov    SI,offset cmd1            ;Point to filename
  427.     call    upper                ;Convert to upper case
  428.     call    ShowIt                ;Show it (not found)
  429.     mov    SI,offset crlf            ;CR,LF
  430.     call    ShowIt                ;On screen
  431.     pop    AX                ;Restore error code
  432. DoneTotally:
  433.     mov    AH,ExitWithCode            ;Terminate with code
  434.     int    DOS                ;Exit program    
  435.  
  436. ; This is the main loop of the program. It is run once for every
  437. ; matching filename found from the command line. Needed variables
  438. ; are reset each time through.
  439.  
  440. Main:
  441.     mov    zooflag,false            ;Reset variables
  442.     mov    byte ptr cmd_cnt,9
  443.     mov    crushed,false
  444.     mov    word ptr buf_pos,0
  445.     mov    flag,false
  446.     mov    count,false
  447.     mov    order,false
  448.     mov    num_hdr,false
  449.     mov    IsZip,false
  450.     mov    IsDWC,false
  451.     mov    IsLZH,false
  452.     mov    Last_Chance,false
  453.  
  454.     mov    DI,offset ExtractOptions    ;Point to last set of options
  455.     mov    CX,9                ;Max options set at 5 bytes
  456.     mov    AL,blank            ;Blank them out (spaces)
  457.     rep    stosb
  458.  
  459.     mov    SI,offset crlf            ;Cr,Lf between runs
  460.     call    ShowIt
  461.     call    wild_card            ;Grab a filename to work on
  462.  
  463. ; If we return from wild_card, at least 1 matching filename was found.
  464. ; Otherwise the program reports its status and quits. If a wild card
  465. ; was used, it has now been extended to a fully qualified filename. Now
  466. ; it has to be checked for archive type etc. etc.
  467.  
  468.     mov    SI,offset msg4            ;SI = 'Searching:'
  469.     call    ShowIt                ;Put it on screen
  470.     mov    SI,offset cmd1            ;SI = filename
  471.     call    upper                ;Convert it to upper case
  472.     call    ShowIt                ;Put it on screen
  473.     cmp    M_Flag,true            ;Displaying net/node?
  474.     jne    NoAddress            ;Skip next part if not
  475.     call    DisplayNode            ;Figure out the info
  476.     mov    SI,offset info4            ;From message
  477.     call    ShowIt                ;Display it
  478.     mov    SI,offset BuildNet        ;Our ASCII info
  479.     call    ShowIt                ;Display it
  480. NoAddress:
  481.     mov    SI,offset crlf            ;SI = cr/lf
  482.     call    ShowIt                ;On screen
  483.  
  484.     mov    SI,offset cmd1            ;SI = full filename
  485.     mov    DI,offset pakfile        ;DI = new command line
  486. do_count:
  487.     lodsb                    ;Get a character from line
  488.     cmp    AL,0                ;End of filename?
  489.     je    done                ;yes, we are finished
  490.     cmp    AL,cr
  491.     je    done1
  492.     inc    byte ptr cmd_cnt        ;Else, bump character counter
  493.     stosb                    ;Save char in command line
  494.     jmp    short do_count            ;and loop back...
  495.  
  496. done:    mov    AL,cr                ;Cmd line must end with cr
  497. done1:    stosb                    ;Stuff final character
  498.  
  499.     mov    byte ptr [DI],0            ;make it ASCIIZ ***
  500.  
  501. ; This little section adds any unique file names that are to be
  502. ; extracted from the archive. If this option is used in conjunction
  503. ; with /d, the archive will be deleted after extraction. BE CAREFUL
  504.  
  505.     cmp    Parsed,true            ;Were filenames specified?
  506.     jne    No_Parsed            ;Skip this if not
  507.     dec    DI                ;Back up destination pointer
  508.     mov    SI,offset Extract_Names        ;SI = extract name buffer
  509.     mov    CX,word ptr Names_Count        ;Get length of names
  510.     add    byte ptr cmd_cnt,CL
  511.     rep    movsb                ;Set up the line
  512.     mov    byte ptr [DI],cr        ;End it all with a cr
  513.     mov    byte ptr [DI+1],0        ;Make it ASCIIZ
  514.  
  515. ; Here is where we check the archive type. If it is a zoo file, it is
  516. ; extracted as is. If it is an ARC/PAK/PK file, it is first checked to
  517. ; ensure that it is in proper order by date time...
  518.  
  519. No_Parsed:
  520.     call    ArchiveCheck            ;Check the archive type
  521.     jnc    Zoo_Check_OK            ;If all is well, continue
  522.     jmp    main                ;Else, try to do the next one
  523.  
  524. Zoo_Check_OK:
  525.     mov    DX,offset UnArc4        ;Point to LOOZ.EXE
  526.     cmp    zooflag,true            ;Is this a zoo file?
  527.     jne    no_zoo
  528.     call    find                ;Does LOOZ exist?
  529.     jc    no_looz                ;Nope, check for zoo
  530.  
  531. ; If execution falls here, LOOZ was found on the path. We have to change
  532. ; the extract option to 'x' as looz does not understand 'e'
  533.  
  534.     cmp    O_Flag,true            ;Do we want forced overwrite?
  535.     jne    DontForceLooz            ;Go if not
  536.     jmp    short no_looz            ;If we do, call zoo instead
  537. DontForceLooz:
  538.     mov    byte ptr ExtractOptions + 1,'x'    ;Change extract option
  539.     jmp    X_OK                ;Go execute looz
  540.  
  541. ; If we get here, a zoo archive was detected, and LOOZ was not found.
  542. ; Check for ZOO.EXE and quit if not found...
  543.  
  544. no_looz:
  545.     mov    DX,offset UnArc7        ;DX = zoo.exe
  546.     cmp    O_Flag,true            ;Do we want forced overwrite?
  547.     jne    DoNotForceZoo            ;Exit if not, else
  548.     mov    byte ptr ExtractOptions +2,'S'    ;This will force overwrite
  549.     mov    byte ptr ExtractOptions +3,'O'    ;This is needed too
  550. DoNotForceZoo:
  551.     mov    byte ptr ExtractOptions +1,'x'    ;Change extract option
  552.     jmp    zoo                ;Go hunt for it
  553.  
  554. no_zoo:    cmp    IsDWC,true            ;Is this a DWC file?
  555.     jne    TryZIP                ;Nope, check for ZIP
  556.     mov    DX,offset UnArc8        ;Point to 'DWC.EXE'
  557.     cmp    O_Flag,true            ;Overwrite mode?
  558.     jne    DoNotForceDwc            ;If not, exit
  559.     mov    byte ptr ExtractOptions + 1,'x'    ;This will allow DWC
  560.     mov    byte ptr ExtractOptions + 2,'w' ;to overwrite existing files
  561.     jmp    Zoo                ;Try to run it
  562. DoNotForceDwc:
  563.     mov    byte ptr ExtractOptions + 1,'e'    ;Normal extract mode
  564.     jmp    Zoo                ;Try to run it
  565.  
  566. TryZIP:    cmp    IsZIP,true            ;Is this a ZIP file?
  567.     jne    TryLZH                ;If not, check for LHArc
  568.     mov    DX,offset UnArc9        ;Point to 'PKUNZIP.EXE'
  569.     cmp    O_Flag,true            ;Overwrite mode?
  570.     jne    DoNotForceZIP            ;Exit if not
  571.     mov    byte ptr ExtractOptions + 1,'-'    ;This will allow Zip
  572.     mov    byte ptr ExtractOptions + 2,'o'    ;to overwrite existing files
  573.     jmp    Zoo                ;Try to run it
  574. DoNotForceZIP:
  575.     jmp    Zoo                ;Try to run it
  576.  
  577. TryLZH:    cmp    IsLZH,true            ;Is this an LHZ file?
  578.     jne    TryNormal            ;Must be an ARC
  579.     mov    DX,offset UnArc10        ;Point to 'LHARC.EXE'
  580.     mov    byte ptr ExtractOptions,'e'    ;Must have extract option
  581.     cmp    O_Flag,true            ;Overwrite mode?
  582.     jne    DoNotForceLZH            ;Exit if not
  583.     mov    byte ptr ExtractOptions + 2,'/'    ;This will allow LHArc
  584.     mov    byte ptr ExtractOptions + 3,'m'    ;to overwrite existing files
  585.     mov    byte ptr ExtractOptions + 4,'c'    ;Not very exotic....
  586.     jmp    Zoo                ;Try to run it
  587. DoNotForceLZH:
  588.     jmp    Zoo                ;Try to run it
  589.  
  590. TryNormal:
  591.     call    Sort_It
  592.     jnc    part2                ;Sort was good, go unarc
  593.  
  594.     mov    SI,offset sorterr        ;Point to error message
  595.     call    ShowIt                ;Put it on screen
  596.  
  597. Part2:
  598.     mov    byte ptr ExtractOptions + 1,'e'    ;Normal extract option
  599.     cmp    Crushed,true            ;Crushed files?
  600.     jne    part3                ;Nope, check for ARCE
  601.  
  602. Part2a:    mov    DX,offset UnArc5        ;Point to PAK.EXE
  603.     cmp    O_Flag,true            ;Overwrite mode?
  604.     jne    DoNotForcePak            ;Exit if not
  605.     mov    byte ptr ExtractOptions + 2,' ' ;A space for the new PAK
  606.     mov    byte ptr ExtractOptions + 3,'/' ;A hyphen for the new PAK
  607.     mov    byte ptr ExtractOptions + 4,'w' ;This tells pak to force
  608.     mov    byte ptr ExtractOptions + 5,'a' ; overwrites always
  609. DoNotForcePak:
  610.     cmp    byte ptr D_flag,true        ;Was delete flag set?
  611.     jne    NoDelete            ;Nope, continue...
  612.     mov    byte ptr ExtractOptions + 1,'x'    ;Delete archive when done
  613. NoDelete:
  614.     jmp    zoo                ;Do PAK and PAK only.
  615.  
  616. part3:    cmp    byte ptr A_Flag,true        ;Default to ARCE?
  617.     jne    Xarc                ;Go if not
  618.  
  619. NoneFound:
  620.     cmp    Crushed,true            ;Crushed files?
  621.     jne    OkForArce            ;Nope, keep going
  622.     jmp    Give_Up                ;If yes, just quit
  623. OkForArce:
  624.     cmp    O_Flag,true            ;Force overwrite mode?
  625.     jne    DontForceArce            ;Go if not
  626.  
  627.     mov    SI,offset pakfile        ;Point to command line
  628. goagain:
  629.     lodsb
  630.     or    AL,AL
  631.     jnz    goagain
  632.     mov    DI,SI                ;Get address in DI
  633.     mov    byte ptr [DI-2],Blank        ;Put in a space
  634.     mov    byte ptr [DI-1],'/'        ;and an Option delimiter
  635.     mov    byte ptr [DI],'R'        ;and Force overwrites...
  636.     mov    byte ptr [DI+1],cr
  637.     mov    byte ptr [DI+2],0
  638.     add    byte ptr cmd_cnt,3        ;Fix the count up
  639.  
  640. DontForceArce:
  641.     mov    DX,offset UnArc6        ;Else point to it
  642.     mov    byte ptr ExtractOptions + 1,' '    ;This removes any options
  643.     mov    byte ptr ExtractOptions + 2,' '    ; that may have been put
  644.     mov    byte ptr ExtractOptions + 3,' '    ; in by other un-archers
  645.     jmp    short zoo            ;Go try to run it
  646.  
  647. Xarc:    mov    DX,offset UnArc1        ;Point to PKXARC.EXE
  648.     mov    byte ptr ExtractOptions + 1,' '    ;Remove 'e' option
  649.     cmp    O_Flag,true            ;Overwrite mode?
  650.     jne    DoNotForceXarc            ;Exit if not
  651.     mov    byte ptr ExtractOptions + 1,'-'    ;This forces PKWare to use
  652.     mov    byte ptr ExtractOptions + 2,'r'    ; it's overwrite mode
  653. DoNotForceXarc:
  654.     call    find                ;See if it exists
  655.     jnc    X_OK                ;Got it!
  656.  
  657.     mov    DX,offset UnArc2        ;Point to PKXARC.COM
  658.     call    find                ;See if it exists
  659.     jnc    X_OK                ;Got it!
  660.  
  661.     mov    DX,offset UnArc3        ;Point to PKUNPAK.EXE
  662.     call    find                ;See if it exists
  663.     jnc    X_OK                ;Got it, keep going
  664.  
  665.     mov    DX,offset UnArc5        ;Point to PAK.EXE
  666.     mov    byte ptr ExtractOptions + 1,'e'    ;Set up extract for pak
  667.     cmp    O_Flag,true            ;Overwrite mode?
  668.     jne    DontForcePak            ;Exit if not
  669.     mov    byte ptr ExtractOptions + 2,' ' ;A space for the new PAK
  670.     mov    byte ptr ExtractOptions + 3,'/' ;A hyphen for the new PAK
  671.     mov    byte ptr ExtractOptions + 4,'w' ;This tells pak to force
  672.     mov    byte ptr ExtractOptions + 5,'a' ;overwrite always
  673. DontForcePak:
  674.     cmp    byte ptr D_flag,true        ;Was delete flag set?
  675.     jne    part3a                ;Nope, continue...
  676.     mov    byte ptr ExtractOptions + 1,'x'    ;Delete archive when done
  677.  
  678. part3a:    call    find                ;See if it exists
  679.     jnc    X_OK                ;Got it, continue
  680.     jmp    NoneFound            ;Try Arce....
  681.  
  682. Zoo:    call    find                ;See if it exists
  683.     jnc    X_OK                ;Got it!
  684.  
  685. ; If this code is executed, then no Un-Arc program was found on the
  686. ; path. It reports the error and aborts...
  687.  
  688. Give_Up:
  689.     mov    AX,22                ;Unarcher not found
  690.     call    err_msg                ;Report error in english
  691.     mov    AH,ExitWithCode            ;Exit with code
  692.     int    DOS                ;Back to DOS (for good)
  693.  
  694. X_OK:    mov    BX,offset par_blk        ;BX points to spawn info
  695.     mov    AL,0                ;AL = load and execute
  696.     push    DS    
  697.     push    ES
  698.     cli                    ;Disable interupts
  699.     mov    stk_seg,SS            ;Save the Stack
  700.     mov    stk_ptr,SP            ;Both parts...
  701.     sti                    ;Enable inerupts
  702.     mov    AH,ExecuteProgram        ;AH = MSDOS exec function
  703.     int    DOS                ;Transfer to DOS
  704.     cli                    ;disable interupts
  705.     mov    SS,stk_seg            ;Restore stack segment
  706.     mov    SP,stk_ptr            ;Restore stack pointer
  707.     sti                    ;Enable interupts
  708.     pop    ES
  709.     pop    DS
  710.  
  711.     mov    AH,GetReturnCode        ;Get return code from Un-Arcer
  712.     int    DOS                ;Transfer to DOS
  713.     mov    elevel,AL            ;Save errorlevel for later
  714.  
  715.     cmp    byte ptr crushed,true        ;Did we use PAK?
  716.     jne    normal                ;Nope, check for delete flag
  717.  
  718.     cmp    byte ptr D_Flag,true        ;Did we mark for delete?
  719.     jne    main_loop            ;Exit if no
  720.  
  721.     mov    SI,offset del_msg        ;SI = 'Unlinking...'
  722.     call    ShowIt
  723.     mov    SI,offset cmd1            ;SI = filename
  724.     call    ShowIt
  725.     mov    SI,offset crlf
  726.     call    ShowIt
  727.     jmp    short main_loop            ;Go do next file
  728.  
  729. normal:    or    AL,AL                ;Make sure all is well
  730.     jnz    main_loop            ;Before allowing a delete
  731.  
  732.     cmp    byte ptr D_Flag,true        ;Should we delete arc file?
  733.     jne    main_loop            ;Skip if not
  734.  
  735.     mov    SI,offset del_msg        ;SI = 'Unlinking...'
  736.     call    ShowIt
  737.     mov    SI,offset cmd1            ;SI = filename
  738.     call    ShowIt
  739.     mov    SI,offset crlf
  740.     call    ShowIt
  741.  
  742.     mov    AH,DeleteFile            ;AH = delete file
  743.     mov    DX,offset cmd1            ;DX = archive name
  744.     int    DOS                ;Call DOS to do it
  745.     jnc    main_loop            ;Go if no errors
  746.     call    err_msg                ;Show errors but continue...
  747. main_loop:
  748.     jmp    main                ;Go get next file
  749.  
  750.  
  751. ; Print ASCIIZ string pointed to by SI
  752.  
  753. ShowIt:
  754.     mov    AH,CharacterOutput        ;Function = console out
  755.     mov    byte ptr Characters,0        ;Set count to zip
  756. show_loop:    lodsb                ;Get a character
  757.     or    AL,AL                ;Is it a 0?
  758.     jz    ShowIt_exit            ;If yes, exit
  759.     inc    byte ptr Characters        ;Bump char counter
  760.     mov    DL,AL                ;ASCII char in DL
  761.     int    DOS                ;Call DOS to print it
  762.     jmp    short show_loop            ;Go get more
  763. ShowIt_exit:
  764.     ret                    ;Return to caller
  765.  
  766. Spaz    endp
  767.  
  768. argc    proc    near                ;count command line arguments
  769.  
  770.     push    BX                ;save original BX and CX
  771.     push    CX                ;  for later
  772.     mov    AX,1                ;force count >= 1
  773. argc1:    mov    CX,-1                ;set flag = outside argument
  774. argc2:    inc    BX                ;point to next character
  775.     cmp    byte ptr [BX],cr
  776.     je    argc3                ;exit if carriage return
  777.     cmp    byte ptr [BX],blank
  778.     je    argc1                ;out of argument if blank
  779.     cmp    byte ptr [BX],tab
  780.     je    argc1                ;outside argument if ASCII tab
  781.                         ;otherwise not blank or tab,
  782.     jcxz    argc2                ;jump if already in argument
  783.     inc    AX                ;else found argument, count it
  784.     not    CX                ;set flag = inside argument
  785.     jmp    argc2                ;and look at next character
  786.  
  787. argc3:    pop    CX                ;restore original BX and CX
  788.     pop    BX
  789.     ret                    ;return AX = argument count
  790.  
  791. argc    endp
  792.  
  793.  
  794. argv    proc    near                ;get address & length of
  795.                         ;command tail argument
  796.     xor    AH,AH                ;initialize argument countef
  797. argv1:    mov    CX,-1                ;set flag = outside argument
  798. argv2:    inc    BX                ;point to next character
  799.     cmp    byte ptr [BX],cr
  800.     je    argv7                ;exit if carriage return
  801.     cmp    byte ptr [BX],blank
  802.     je    argv1                ;outside argument if ASCII blank
  803.     cmp    byte ptr [BX],tab
  804.     je    argv1                ;outside argument if ASCII tab
  805.                         ;if not blank or tab...
  806.     jcxz    argv2                ;jump if already inside argument
  807.     inc    AH                ;else count arguments found
  808.     cmp    AH,AL                ;is this the one we're looking for?
  809.     je    argv4                ;yes, go find its length
  810.     not    CX                ;no, set flag = inside argument
  811.     jmp    argv2                ;and look at next character
  812.  
  813. argv4:                        ;found desired argument, now
  814.                         ;determine its length...
  815.     mov    AX,BX                ;save param, starting address
  816.  
  817. argv5:    inc    BX                ;point to next character
  818.     cmp    byte ptr [BX],cr
  819.     je    argv6                ;found end if carriage return
  820.     cmp    byte ptr [BX],blank
  821.     je    argv6                ;found end if ASCII blank
  822.     cmp    byte ptr [BX],tab
  823.     jne    argv5                ;found end if ASCII tab
  824.  
  825. argv6:    xchg    BX,AX                ;set ES:BX = argument address
  826.     sub    AX,BX                ;and AX = argument length
  827.     jmp    short argvx            ;return to caller
  828. argv7:    xor    AX,AX                ;set AX = 0, argument not found
  829. argvx:    ret                    ;return to caller
  830.  
  831. argv    endp
  832.  
  833.  
  834. getenv    proc    near                    ; return address and length
  835.                         ;   of environment variable
  836.  
  837.     push    CX                ; save registers
  838.     push    SI
  839.  
  840.     mov    CX,8000h            ; assume max env. = 32 KB
  841.     xor    DI,DI                ; initial env. offset
  842.     xor    AX,AX                ; default length result 
  843. get1:    cmp     byte ptr ES:[DI],0        ; check for end of environment
  844.     je    get4                ; end reached, return AX = 0
  845.     pop    SI                ; initialize address of target
  846.     push    SI                ;   variable to be found
  847.  
  848.     repe    cmpsb                ;Compare target and env. strings
  849.     cmp    byte ptr [SI-1],0
  850.     jne    get2                ;Jump if incomplete match
  851.     cmp    byte ptr ES:[DI-1],'='
  852.     je    get3                ;Jump if match was complete
  853.  
  854. get2:    repne    scasb                ;No match, scan for end string
  855.     jmp    get1                ;Try again to match
  856.  
  857. get3:    push    DI                ;Save address after = sign
  858.     repne    scasb                ;Look for end of this string
  859.     pop    AX                ;Get back starting address 
  860.     xchg    DI,AX                ;Find string length
  861.         sub     AX,DI
  862.     dec    AX                ;Don't include null byte
  863.  
  864. get4:    pop    SI                ;Common exit point
  865.     pop    CX
  866.     mov    CS:env_len,AX            ;Save PATH length
  867.     or    AX,AX                ;Null PATH?
  868.     jz    get5                ;Exit if yes
  869.     push    ES                ;Get path segment into
  870.     pop    DS                ; DX for string move
  871.     push    CS                ;Now ES points to data
  872.     pop    ES                ; in our code segment
  873.     mov    CX,AX                ;Get length of path in CX
  874.     mov    SI,DI                ;Path is now source
  875.     mov    DI,offset saved            ;Destination is our area
  876.     rep    movsb                ;Move path into this segment
  877. get5:    push    CS                ;Now we have to restore
  878.     pop    DS                ; the original DS
  879.     push    CS
  880.     pop    ES
  881.     ret                    ;Return to caller
  882. getenv  endp
  883.  
  884.  
  885. ; This routine searches the current directory, and (if needed), the
  886. ; entire PATH, looking for an unarchiver to use. It is called with
  887. ; DX pointing to an ASCIIZ filename to look for and returns with
  888. ; carry clear if it is found. Carry Set if not found.
  889.  
  890. find    proc    near
  891.     push    DX                ;Save pointer to filename
  892.     mov    AH,SearchForFirst        ;Search for first
  893.     pop    DX                ;Get filename address
  894.     push    DX                ;Save it again
  895.     xor    CX,CX                ;Normal attribute
  896.     int    DOS                ;Give it to DOS
  897.     jc    find1                ;Not found, search path
  898.     pop    DX                ;Point DX to filename
  899.     ret                    ;exit Find...
  900.  
  901. find1:    mov    AX,env_len            ;Get PATH length
  902.     or    AX,AX                ;Did we find a path?
  903.     jnz    find2                ;Keep going if yes
  904. no_exist:
  905.     pop    DX                ;Point DX to filename
  906.     stc                    ;Carry set to show error
  907.     ret                    ;Exit Find
  908.  
  909. find2:    mov    DI,offset saved            ;Point to the path string
  910.     mov    dir,DI                ;dir = start of path string
  911.     add    DI,AX                ;AX = end of path string
  912.     mov    enddir,DI            ;save it
  913.     mov    byte ptr [DI],0            ;Null terminator for path
  914.  
  915. find3:    mov    DI,offset new            ;Area for path\filename
  916.     mov    SI,dir                ;Get current address in path
  917.  
  918.     cmp    [enddir],SI            ;End of path variable?
  919.     jbe    no_exist            ;Not found, exit
  920.  
  921. find4:    lodsb                    ;Get a character
  922.     cmp    AL,';'                ;Seperator?
  923.     je    find5                ;Yes, go tack on filename
  924.     cmp    AL,0                ;Are we finished?
  925.     je    find5                ;Yes, go
  926.     stosb                    ;Stuff character
  927.     jmp short find4                ;and go for another
  928.  
  929. find5:    mov    dir,SI                ;Save current path address
  930.     cmp    byte ptr [DI-1],'\'        ;Path separator?
  931.     je    find6                ;Yup, keep goin
  932.     mov    byte ptr [DI],'\'        ;Else, put one in
  933.     inc    DI                ;Bump the pointer
  934.  
  935. find6:    pop    SI                ;Get filename address
  936.     push    SI                ;Save it back again
  937.  
  938. find7:    lodsb                    ;Get character from filename
  939.     cmp    AL,0                ;Got whole filename?
  940.     je    find8                ;Go if yes
  941.     stosb                    ;Else put character in buffer
  942.     jmp    find7                ;Go get the rest
  943.  
  944. find8:    stosb                    ;Save the null (ASCIIZ)
  945.     mov    AH,SearchForFirst        ;Search for first
  946.     mov    DX,offset new            ;Point to path\filename
  947.     xor    CX,CX                ;Normal attribute
  948.     int    DOS                ;Give it to DOS
  949.     jc    find3                ;Not found try next path
  950.     pop    DX                ;Clear junk off stack
  951.     mov    DX,offset new            ;DX = full path\filename
  952.     clc                    ;Show no errors
  953.     ret                    ;Exit (so we can exec it)
  954. find    endp
  955.  
  956.  
  957. ; This routine determines what type of archive is being worked on.
  958. ; It will set a flag to tell SPAZ which un-archiver to try and use.
  959.  
  960. ArchiveCheck    proc    near
  961.  
  962.     mov    AH,OpenFile            ;AH = open file request
  963.     mov    AL,0                ;read access only
  964.     mov    DX,offset cmd1            ;Point to archive name
  965.     int    DOS                ;Call DOS to open it
  966.     jc    probs
  967.  
  968.     xchg    AX,BX                ;Handle in BX
  969.     mov    AH,ReadFile            ;AH = read file
  970.     mov    CX,4                ;Read first 4 bytes
  971.     mov    DX,offset Usage            ;Read byte into usage area
  972.     int    DOS                ;Call DOS to do it
  973.     jc    probs
  974.  
  975.     mov    AH,MoveFilePointer        ;Get ready to adjust
  976.     mov    AL,2                ;From end of file
  977.     mov    CX,0ffffh            ;2 spaces
  978.     mov    DX,0fffeh
  979.     int    DOS                ;Call DOS to do it
  980.     jc    probs
  981.  
  982.     mov    AH,ReadFile            ;Read last 2 bytes
  983.     mov    CX,2
  984.     mov    DX,offset Usage + 4        ;Buffer for save
  985.     int    DOS                ;Call DOS to do it
  986.     jc    probs
  987.  
  988.     mov    AH,CloseFile            ;AH = close file
  989.     int    DOS                ;Call DOS to do it
  990.     jc    probs
  991.  
  992.     mov    AX,word ptr Usage + 4        ;Get DWC bytes
  993.     cmp    AX,4357h            ;Is it a DWC file?
  994.     jne    IsItZoo                ;Go, if not
  995.     mov    IsDWC,true            ;Else set flag
  996.     jmp    short EndCheck            ;And exit
  997.  
  998. IsItZoo:
  999.     mov    AX,word ptr Usage        ;Get value
  1000.     cmp    AX,4f5ah            ;Is it a zoo file?
  1001.     jne    IsItZip                ;Go if not, else
  1002.     mov    zooflag,true            ;Mark for zoo
  1003.     jmp    short EndCheck
  1004.  
  1005. IsItZip:
  1006.     cmp    AX,4b50h            ;Is it a ZIP file?
  1007.     jne    IsItArc                ;Go, if not
  1008.     mov    IsZip,true            ;Set flag
  1009.     jmp    short EndCheck            ;We're outa here
  1010.  
  1011. IsItArc:
  1012.     cmp    AL,1Ah                ;Is it a normal Arc/Pak?
  1013.     jne    IsItLZH                ;Skip this file if not
  1014.     jmp    short EndCheck            ;We're outa here
  1015.  
  1016. IsItLZH:
  1017.     mov    AX,word ptr Usage + 2        ;Get LH's ID bytes
  1018.     cmp    AX,6C2Dh            ;Is this an LH Arc?
  1019.     jne    NotAnArchive            ;Report error if not
  1020.     mov    IsLZH,true            ;Mark for LHArc
  1021. EndCheck:
  1022.     clc                    ;Show no errors
  1023.     ret
  1024.  
  1025. probs:    push    AX                ;Save error code
  1026.     call    err_msg                ;Report error in english
  1027.     mov    SI,offset zerr            ;SI = Zoo check error message
  1028.     call    ShowIt                ;Display it
  1029.     pop    AX                ;Restore error code
  1030. NotAnArchive:
  1031.     stc                    ;Show error
  1032.     ret                    ;Return to caller
  1033.  
  1034. ArchiveCheck    endp    
  1035.  
  1036.  
  1037. ; This routine is responsible for sorting ARCType bundles into proper
  1038. ; FidoNet Mail format. i.e. Sorted by date/time. It is accomplished
  1039. ; by sorting all the headers and re-writting the entire archive...
  1040.  
  1041. Sort_It    proc    near
  1042.     cld                    ;Move forward again...
  1043.     xor    AL,AL
  1044.     mov    num_hdr,AL            ;Init header counter
  1045.     mov    flag,false
  1046.  
  1047.     mov    DX,offset cmd1            ;DX = Archive filename
  1048.  
  1049.     mov    AH,OpenFile            ;AX = Open file
  1050.     xor    AL,AL                ;Normal Attribute
  1051.     int    DOS                ;Give it to DOS
  1052.     jnc    open_ok                ;Continue if it worked
  1053.     jmp    short inv_hdr            ;Go report errors
  1054.  
  1055.  
  1056. ; This routine will read in the archive file headers so that they
  1057. ; can be sorted.
  1058.  
  1059. open_ok:
  1060.     mov    in_handle,AX            ;Save file handle
  1061.     mov    buf_pos,0            ;Init buffer position
  1062.     call    read_hdr            ;Read in first header
  1063.     jnc    got_1st                ;If clear, we're OK
  1064.  
  1065. ; Truncated file. Somethings weird in Denmark!
  1066.  
  1067.     mov    AX,19                ;Truncated file
  1068. inv_hdr:
  1069.     call    err_msg                ;Put it on screen
  1070.     stc
  1071.     ret                    ;Exit Sort_It with error
  1072.  
  1073.  
  1074. ; If we get this far, the first header has been read in. Stuff it in
  1075. ; the buffer and go for the rest...
  1076.  
  1077. got_1st:
  1078.     mov    SI,cmdtail            ;Point to arc data
  1079.     cmp    byte ptr [SI+1],0        ;End of Archive?
  1080.     jne    Chk_Crushed            ;Exit for sort
  1081.     jmp    got_em
  1082. Chk_Crushed:
  1083.     cmp    byte ptr [SI+1],10        ;Crushed file?
  1084.     jb    Not_Crushed            ;Nope, continue
  1085.     mov    Crushed,true            ;Else, show crushed
  1086. Not_Crushed:
  1087.     cmp    byte ptr [SI],1ah        ;Do we have a PAK file?
  1088.     je    pak_ok                ;If yes, keep going
  1089.     mov    AX,20                ;Invalid header
  1090.     call    err_msg                ;Report error in english
  1091.     add    sp,2                ;Remove return address
  1092.     mov    AH,CloseFile            ;Close the file
  1093.     mov    BX,in_handle
  1094.     int    DOS                ;Call DOS to close file
  1095.     mov    byte ptr elevel,1        ;Report error for no delete
  1096.     jmp    main                ;Bad file, try the next one
  1097.  
  1098. pak_ok:    mov    DI,offset hdr_buf        ;Get buffer address
  1099.     add    DI,[buf_pos]            ;Adjust to current pos
  1100.     mov    AX,low_pos            ;Get file pointer low word
  1101.     mov    [DI],AX                ;Stuff it in buffer
  1102.     mov    AX,high_pos            ;Get file pointer high word
  1103.     mov    [DI+2],AX            ;Stuff it in buffer
  1104.     add    DI,4                ;Adjust the pointer
  1105.     mov    CX,29                ;Length of archive header
  1106.     rep    movsb                ;Put info in buffer
  1107.     add    buf_pos,arc_len            ;Bump the buffer pointer
  1108.  
  1109.     inc    num_hdr
  1110.     cmp    num_hdr,Entries         ;Have we got too many?
  1111.     jb    room                ;Nope, continue...
  1112.  
  1113.     mov    AX,21                ;Too many archive entries
  1114.     jmp    nope                ;Report and exit
  1115.  
  1116. room:    call    read_next            ;Get next header
  1117.     jnc    got_1st                ;Go stuff it in buffer
  1118.     jmp    short got_em            ;Got all headers, exit
  1119.  
  1120. read_next:
  1121.     mov    DI,cmdtail            ;DI = start of header
  1122.     mov    DX,word ptr [DI+15]        ;DX = low byte of arc size
  1123.     mov    CX,word ptr [DI+17]        ;CX = high byte of arc size
  1124.     mov    BX,in_handle            ;BX = opened file handle
  1125.     mov    AH,MoveFilePointer        ;AH = move file pointer
  1126.     mov    AL,1                ;AL = from current position
  1127.     int    DOS                ;Give it to DOS
  1128. read_hdr:
  1129.     mov    BX,in_handle            ;Get opened file handle
  1130.     xor    CX,CX                ;Set offset for search
  1131.     xor    DX,DX                ; to zero bytes
  1132.     mov    AH,MoveFilePointer        ;AH = move file pointrr
  1133.     mov    AL,1                ;AL = from currcnt position
  1134.     int    DOS                ;Call DOS to do it
  1135.     mov    high_pos,DX            ;Save the high word
  1136.     mov    low_pos,AX            ;Save the low word
  1137.     mov BX,in_handle            ;Get opened file handle
  1138.     mov    CX,29                ;Read in 29 bytes
  1139.     mov    DX,cmdtail            ;Buffer for read...
  1140.     mov    AH,ReadFile            ;Read from file
  1141.     int    DOS                ;Give it to DOS
  1142.     ret
  1143.  
  1144. got_em:    mov    Order,true            ;Archive already in order
  1145.  
  1146.     cmp    byte ptr N_Flag,false        ;Skip sort?
  1147.     jne    sort                ;If yes, exit
  1148.     mov    BX,in_handle            ;Get the file handle
  1149.     mov    AH,CloseFile            ;So we can close it
  1150.     int    DOS                ;Call DOS to do it
  1151.     jmp    Back_to_main            ;Exit sort
  1152.  
  1153. sort:    mov    flag,false            ;Show no changes made
  1154.     mov    count,1                ;To prevent sort past end
  1155.     mov    AH,num_hdr            ;Get number of entrys
  1156.     cmp    AH,1                ;Is there only 1 entry?
  1157.     jbe    sort_exit            ;No sort if 0 or 1 entry
  1158.  
  1159.     mov    SI,offset hdr_buf        ;SI = start of header buffer
  1160.     mov    DI,offset hdr_buf+arc_len    ;DI = 2nd entry in buffer
  1161. sort1:    mov    BX,23                ;BX = offset to header date
  1162.     mov    AX,[SI+BX]            ;Get date from 1st entry
  1163.     mov    DX,[DI+BX]            ;Got date from 2nd entry
  1164.     cmp    AX,DX                ;Which is higher?
  1165.     ja    change                ;Swap if 1st > 2nd
  1166.     jne    sort2                ;If not = get next entry
  1167.     mov    BX,25                ; else get offset to time
  1168.     mov    AX,[SI+BX]            ;Get time from 1st entry
  1169.     mov    DX,[DI+BX]            ;Get time from 2nd entry
  1170.     cmp    AX,DX                ;Which is higher?
  1171.     ja    change                ;Swap if 1st > 2nd
  1172.  
  1173. ; If Date and Time are identical, no changes are made
  1174.  
  1175. sort2:    add    SI,arc_len            ;Point to next entry
  1176.     add    DI,arc_len            ;Point to next entry
  1177.     inc    count                ;Bump # of entries completed
  1178.     mov    AH,count            ;Get the number
  1179.     cmp    AH,num_hdr            ;Done all entries?
  1180.     je    pass                ;End of this pass if yes
  1181.     jmp    short sort1            ;Else do next entry
  1182.  
  1183. ; This section will swap the entry pointed to by SI with the entry
  1184. ; pointed to by DI...
  1185.  
  1186. change:    push    SI                ;Save pointer to 1st entry
  1187.     push    DI                ;Save pointer to 2nd entry
  1188.     mov    CX,arc_len            ;# of bytes in an entry
  1189. chg1:    mov    AL,[DI]                ;Get byte from destination
  1190.     movsb                    ;Move Source to Destination
  1191.     mov    [SI-1],AL            ;Move Destination to Source
  1192.     loop    chg1                ;Loop back for more
  1193.     pop    DI                ;Restore 2nd entry address
  1194.     pop    SI                ;Restore 1st entry address
  1195.     mov    flag,true            ;A swap has been made (pass)
  1196.     mov    Order,false            ;Show swap made (constant)
  1197.     jmp    sort2                ;Do next entry
  1198.  
  1199. ; Here we check if a change was made. If no changes were made
  1200. ; then the archive was already in order...
  1201.  
  1202. pass:    mov    AH,flag                ;Get the sort flag
  1203.     cmp    AH,true                ;Was a change made?
  1204.     je    sort                ;Go again if change was made
  1205.  
  1206. sort_exit:
  1207.     mov    AL,Order            ;Was archive in order?
  1208.     cmp    AL,true                ;If yes, do not write
  1209.     jne    write
  1210.     mov    BX,in_handle            ;Get the file handle
  1211.     mov    AH,CloseFile            ;So we can close it
  1212.     int    DOS                ;Call DOS to do it
  1213.     jmp    Back_to_main            ;The file out again.
  1214.  
  1215. write:
  1216.     mov    DI,offset tempspec        ;point to temp filespec  .jjn
  1217.     mov    SI,offset cmd1            ;get location of command .jjn
  1218.     mov    CX,pathlen            ;get path length         .jjn
  1219.     rep movsb                ;make a copy             .jjn
  1220.     mov    SI,offset temp            ;Point to temp filename  .jjn
  1221.     mov    CX,thomlen            ;get length of filename  .jjn
  1222.     rep movsb                ;copy it after the path  .jjn
  1223.     mov    DX,offset tempspec        ;Point to temp filespec  .jjn
  1224.     xor    CX,CX                ;Use normal attribute
  1225.     mov    AH,CreateFile            ;AH = create or truncate
  1226.     int    DOS                ;Call DOS to do it
  1227.     jnc    create_ok            ;Go if all is well
  1228. nope:    call    err_msg                ;Report error in english
  1229.     stc                    ;Carry = Sort failed
  1230.     ret                    ;Back to main section
  1231.  
  1232. ; Here, the temp file has been created and the handle for that file is
  1233. ; in AX.
  1234.  
  1235. create_ok:
  1236.     mov    out_handle,AX            ;Save handle for write file
  1237.  
  1238. ; Now, we have to read in the sorted entry info, and gather more stuff
  1239. ; from the archive headers
  1240.  
  1241.     mov    SI,offset hdr_buf        ;Point to the sorted info
  1242.     mov    AL,num_hdr            ;Get number of entries
  1243. nxt_hdr:
  1244.     mov    flag,false            ;Use flag for eof check
  1245.     push    AX                ;Save # of entries for later
  1246.     push    SI                ;Save buffer pointer
  1247.     mov    DX,[SI]                ;Get low word of file position
  1248.     mov    CX,[SI+2]            ;Get high word of position
  1249.     mov    low_pos,DX
  1250.     mov    high_pos,CX
  1251.  
  1252.     clc
  1253.     add    DX,29                ;Adjust for arc header
  1254.     adc    CX,0                ;Include carry if any
  1255.  
  1256.     mov    BX,in_handle            ;Get read file handle
  1257.     mov    AL,0                ;Offset is from beginning
  1258.     mov    AH,MoveFilePointer        ;AH = move file pointer
  1259.     int    DOS                ;Call DOS to do it
  1260.  
  1261. ; The file pointer has been set to the read location. First we
  1262. ; write the header. Then we read and write the archive data.
  1263.  
  1264. hdr_in:    call    info                ;Print the copy info
  1265.     pop    DX                ;Get buffer pointer
  1266.     push    DX                ;And save it again
  1267.     add    DX,4                ;Skip past file location
  1268.     mov    CX,29                ;Number of bytes to write
  1269.     mov    BX,out_handle            ;Get the write file handle
  1270.     mov    AH,WriteFile            ;AH = write to file
  1271.     int    DOS                ;Call DOS to write the header
  1272.     jnc    hdr_out                ;Header written ... go
  1273.     add    sp,4                ;Get rid of stack junk
  1274.     jmp    short nope            ;Exit, we had problems
  1275.  
  1276. hdr_out: 
  1277.     pop    SI                ;Point to the header
  1278.     push    SI                ;Save it back
  1279.     mov    DX,[SI+21]            ;Get high word of entry size
  1280.     mov    AX,[SI+19]            ;Get low word of entry size
  1281.  
  1282. ; DX:AX contains the number of bytes that have to be read/written.
  1283.  
  1284.     xor     CX,CX                ;High word of buffer size
  1285.     mov    BX,bsize            ;Low word of buffer size
  1286.  
  1287. ; CX:BX contains the number of bytes we can do at one time.
  1288.  
  1289. cont:    clc                    ;Get ready for subtract
  1290.     sub    AX,BX                ;Subtract low word
  1291.     sbb    DX,CX                ;Subtract high word
  1292.     push    AX
  1293.     push    DX
  1294.     push    BX
  1295.     push    CX
  1296.     jae    more1                ;There's still more to go
  1297.  
  1298.     clc
  1299.     add    BX,AX                ;Add back last result
  1300.     mov    flag,true            ;Show end of data reached
  1301.  
  1302. ; Here BX contains the remaining number of bytes to read write.
  1303. ; So we have to put it in CX
  1304.  
  1305. more1:    xchg    BX,CX                ;Get count in CX
  1306.     mov    DX,offset cpy_buf        ;Point to our buffer
  1307.     mov    BX,in_handle            ;Handle for read
  1308.     mov    AH,ReadFile            ;AH = read file
  1309.  
  1310. ; Note: CX should contain [bsize] OR the  remaining bytes to go...
  1311.  
  1312.     int    DOS                ;Call DOS to read file
  1313.     jnc    data_ok                ;Got the data
  1314.     add    sp,12                ;Remove stack junk
  1315.     jmp    nope                ;Exit, we had probs...
  1316.  
  1317. data_ok:
  1318.     mov    BX,out_handle            ;Handle for write
  1319.     mov    AH,WriteFile            ;AH = write to file
  1320.     int    DOS                ;Call DOS to write out buffer
  1321.     jnc    write_ok            ;Go if all is well, else
  1322.     add    sp,12                ;Remove junk from stack
  1323.     jmp    nope                ;Exit...
  1324.  
  1325. write_ok:
  1326.     cmp    flag,true            ;Was this end of arc data?
  1327.     je    do_next                ;Get next header if yes
  1328.     pop    CX                ;Low word buffer size
  1329.     pop    BX                ;Low word file size
  1330.     pop    DX                ;High word file size
  1331.     pop    AX                ;Low word buffer size
  1332.     jmp    cont                ;Continue with this entry
  1333. do_next:
  1334.     add    SP,8                ;Clear junk off stack
  1335.     pop    SI                ;Get back buffer position
  1336.     add    SI,33                ;Adjust to next entry
  1337.     pop    AX                ;Get back number of entrys
  1338.     dec    AL                ;Subtract 1 from it
  1339.     jz    no_more                ;We're done with data
  1340.     jmp    nxt_hdr                ;Else go get the next one
  1341. no_more:
  1342.  
  1343. ; Before we quit, we have to write out a 1A 00 to show the end of
  1344. ; the archive.
  1345.  
  1346.     mov    AH,WriteFile            ;AH = write to file
  1347.     mov    BX,out_handle            ;Handle for write file
  1348.     mov    CX,2                ;Number of bytes to write
  1349.     mov    DX,offset end_arc        ;Point to the data
  1350.     int    DOS                ;Call DOS to do it
  1351.     jnc    delete                ;We're finished !
  1352.     jmp    nope                ;Exit sort routine
  1353.  
  1354. ; Now that the meat of the work is done, we have to delete the old
  1355. ; arc file and rename the new one.
  1356.  
  1357. delete:    mov    BX,in_handle
  1358.     mov    AH,CloseFile
  1359.     int    DOS
  1360.     mov    BX,out_handle
  1361.     mov    AH,CloseFile
  1362.     int    DOS
  1363.  
  1364.     mov    DX,offset cmd1            ;Point to original name
  1365.     mov    AH,DeleteFile            ;AH = delete file
  1366.     int    DOS                ;Call DOS to do it
  1367.     jnc    del_ok
  1368.     jmp    nope
  1369.  
  1370. del_ok:    mov    AH,RenameFile            ;AH = rename file
  1371.     mov    DI,offset cmd1            ;Original filename
  1372.     mov    DX,offset tempspec        ;Temporary filename        .jjn
  1373.     int    DOS                ;Call DOS to do it
  1374.     jnc    Back_to_main            ;Go if no problems
  1375.     jmp    nope                ;Exit program...
  1376. Back_to_main:
  1377.     clc                    ;Sort done. No errors
  1378.     ret                    ;Return to main section
  1379.  
  1380. ; Convert double word to ascii decimal. Uses divide instruction
  1381. ; Parameters passed in registers as follows:
  1382. ;    DX:AX =    binary word to be converted
  1383.  
  1384. DecimalOut:
  1385.     push    DI
  1386.     push    AX
  1387.     mov    DI,offset decbuf        ; address of output buffer
  1388.     mov    CX,7                ; buffer length-1
  1389.     mov    AL,' '                ; pad character
  1390.     rep    stosb                ; clear buffer & point to end
  1391.     mov    byte ptr [DI], 0        ; init end of string
  1392.     dec    DI
  1393.     pop    AX                ;Get low word back
  1394.     xchg    BP,DX                ;Save high word
  1395.     mov    BX,10                ;Use base 10 for decimal
  1396.     mov    CL,30h                ;For conversion to ASCII
  1397. HighWordLoop:
  1398.     or    BP,BP                ;Are we done with high words?
  1399.     jz    LowWordLoop            ;Yes
  1400.     xchg    AX,BP                ;No, get high word
  1401.     xor    DX,DX                ;Clear DX
  1402.     div    BX
  1403.     xchg    BP,AX                ;Save new high word
  1404.     div    BX                ;Divide low word + remainder
  1405.     or    DL,CL                ;Convert hex value to ASCII
  1406.     mov    [DI],DL                ;Save decimal character
  1407.     dec    DI                ;Back up in the buffer
  1408.     jmp    HighWordLoop            ;Repeat until done
  1409. LowWordLoop:
  1410.     xor    DX,DX                ;Clear DX
  1411.     div    BX
  1412.     or    DL,CL                ;Convert hex value to ASCII
  1413.     mov    [DI],DL                ;Save decimal character
  1414.     dec    DI                ;Back up in the buffer
  1415.     or    AX,AX                ;Are we done?
  1416.     jnz    LowWordLoop            ;No
  1417.  
  1418.     pop    DI
  1419.     ret
  1420. Sort_It    endp
  1421.  
  1422.  
  1423. ;Convert an ASCIIZ string to upper case.
  1424. ; Call with SI pointing to string to be converted
  1425.  
  1426. upper    proc    near
  1427.     push    SI                ; save string address
  1428. up1:    lodsb                    ; next character
  1429.         or    AL,AL                ; found end (null byte) ? 
  1430.         jz      up2                ; yes, jump
  1431.         cmp     AL,'a'                ; test if in range 'a'-'z'
  1432.         jb      up1                ; skip it if not >= a
  1433.         cmp     AL,'z'
  1434.         ja      up1                ; skip it if not <= z
  1435.         sub     byte ptr [SI-1],'a'-'A'        ; change char to upper case
  1436.         jmp     up1                ; get another char
  1437.  
  1438. up2:    pop    SI                ; restore original string
  1439.     ret                    ; address and return
  1440. upper    endp
  1441.  
  1442.  
  1443. ; This routine is called by the sort. It prints a line of information
  1444. ; for every entry in the archive detailing its size, filename, and
  1445. ; new locatio in the archive....
  1446.  
  1447. info    proc    near
  1448.     mov    SI,offset msg1            ;SI = 'Adjusting'
  1449.     call    ShowIt                ;Put it on screen
  1450.     mov    BP,SP                ;Get stack pointer
  1451.     mov    SI,[BP+2]            ;SI = address of arc entry
  1452.     add    SI,6                ;Now SI points to filename
  1453.     push    SI                ;Save address for later
  1454.     call    ShowIt                ;Put it on screen
  1455.  
  1456.     mov    CX,14                ;Tab length for info screen
  1457.     sub    CL,Characters            ;Subtract # of chars printed
  1458.     mov    DL,blank            ;AL = space
  1459.     mov    AH,CharacterOutput        ;Function = console out
  1460. info_loop:
  1461.     int    DOS                ;Call DOS to print space
  1462.     loop    info_loop            ;Loop till tab is complete
  1463.  
  1464.     mov    SI,offset msg2            ;SI = 'Location ='
  1465.     call    ShowIt                ;Put it on screen
  1466.     mov    DX,high_pos            ;High word file position
  1467.     mov    AX,low_pos            ;Low word file position
  1468.     call    DecimalOut            ;Convert to ASCII and print
  1469.     mov    SI,offset decbuf        ;Yes, String address to SI
  1470.     call    ShowIt                ; Output it
  1471.     mov    SI,offset msg3            ;SI = 'Length ='
  1472.     call    ShowIt                ;Put it on screen
  1473.     pop    SI                ;Restore Arc filename address
  1474.     mov    AX,[SI+13]            ;Low word file size
  1475.     mov    DX,[SI+15]            ;High word file size
  1476.     clc                    ;Get ready for addition
  1477.     add    AX,29                ;Add in length of header
  1478.     adc    DX,0                ;Add in any carry
  1479.     call    DecimalOut            ;Convert to ASCII and print
  1480.     mov    SI,offset decbuf        ;Yes, String address to SI
  1481.     call    ShowIt                ; Output it
  1482.     mov    SI,offset crlf            ;SI = cr/lf
  1483.     call    ShowIt                ;Put it on screen
  1484.     ret                    ;Return to caller
  1485. info    endp
  1486.  
  1487. ; This routine prints one of DOS's error messages and returns to
  1488. ; which ever section of the code called it...
  1489.  
  1490. err_msg    proc    near
  1491.     push    AX                ;Save errorlevel
  1492.     dec    AX                ;Adjust for beginning of table
  1493.     add    AX,AX                ; * 2 for DW variables
  1494.     mov    SI,AX                ;Get offset in SI
  1495.     mov    SI,errmsg[SI]            ;Now SI = address of string
  1496.     call    ShowIt                ;Put it on screen
  1497.     pop    AX                ;Restore errorlevel
  1498.     ret
  1499. err_msg    endp
  1500.  
  1501.  
  1502. ;************************************************************************
  1503. ; FindNames: find all file names matching the file specification in cmd1.
  1504. ; REGISTERS ON EXIT:
  1505. ;  AX = number of files found (may be 0).
  1506. ;  ZF = reset if files found, set if no files found.
  1507. ; This procedure written by Jeffrey J Nonken. (Modified by Dan)
  1508. ;************************************************************************
  1509.  
  1510.     public    FindNames
  1511. FindNames    proc    near
  1512.     mov    DI,offset save_buf        ;Get dest addresm of filename
  1513.     mov    AL,num_names            ;Get # of names already there
  1514.     mov    CL,13                ;Length of 1 entry
  1515.     mul    CL                ;Names * 13
  1516.     add    DI,AX                ;Now DI points into buffer
  1517.     
  1518.     mov    AH,SearchForFirst        ;AH = Search for first
  1519.     xor    CX,CX                ;Attribute = 'normal'
  1520.     mov    DX,offset cmd1            ;Point to ASCIIZ filename
  1521.     int    DOS                ;Give it to DOS
  1522.     jnc    get1fname            ; Found a file, process it
  1523.     jmp    no_files            ;Finished with search
  1524.  
  1525. ; Loop to here if buffer was written to disk.
  1526.  
  1527. clean_buf:
  1528.     mov    num_names,0            ; no more names in the buffer
  1529.     mov    DI,offset save_buf        ;Get dest address of filename
  1530.  
  1531. ; Loop to here after each file name, look for the next one.
  1532.  
  1533. next:
  1534.     mov    AH,SearchForNext        ;AH = Search for next
  1535.     int    DOS                ;Give it to DOS
  1536.     jnc    get1fname            ; Found a file, process it
  1537.     jmp    short NoMoreFiles        ; If not, quit now.
  1538. get1fname:
  1539.  
  1540. ;Now we move the filename.ext up to our own ASCIIZ string
  1541. ;so that open can use the correct path to the file. 
  1542.  
  1543.     mov    SI,offset dta_buf+30        ;SI = filename found
  1544.     mov    CX,6                ; Name is <= 13 bytes
  1545.                         ;  (including trailing null)
  1546.     rep movsw                ; Move 12 bytes (6 words)
  1547.     movsb                    ; Move the last byte
  1548.     inc    name_count            ; Count up (total count)
  1549.     inc    num_names            ; Count up (buffer count)
  1550.     cmp    num_names,NamesFound        ; See if we have names yet
  1551.     jb    next                ; Just repeat if not
  1552.  
  1553. ; If we got here, there were at least 'NamesFound' names.
  1554. ; Start writing them to disk.
  1555.  
  1556.     cmp    on_disk,0            ; See if there's a file open
  1557.     jnz    already_open            ; If so, skip the open step
  1558.     mov    DX,offset filename_file        ; Get the file's name
  1559.     mov    AH,CreateFile            ; Open the file
  1560.     xor    CX,CX                ;No attributes
  1561.     int    DOS                ; Do it
  1562.     mov    files_handle,AX            ; Save the file handle(error)
  1563.     jnc    already_open            ; If no errors, write to file
  1564.     call    err_msg                ;Report error in english
  1565.     mov    DX,offset TempErr        ;Unable to create file
  1566.     mov    AH,OutputString            ;DOS print string function
  1567.     int    DOS                ;Display error
  1568.     jmp    short NoMoreFiles        ;Continue on
  1569.  
  1570. ; If the temporary file can't be created, we exit here. This will allow
  1571. ; SPAZ to process at least 'NamesFound' archives before quitting. If this
  1572. ; is a disk full condition, it will be reported by the un-archiver.
  1573.  
  1574. already_open:
  1575.     mov    DX,offset save_buf        ; point to buffer
  1576.     mov    BX,files_handle            ; get the file handle
  1577.     mov    CX,13 * NamesFound        ; number of file names to write
  1578.     mov    AH,WriteFile            ; write to the file
  1579.     int    DOS
  1580.     mov    on_disk,1            ; say it's on disk
  1581.     jmp    clean_buf            ; loop around and clear buffer
  1582.  
  1583. ; No more files found. Clean up and exit.
  1584.  
  1585. NoMoreFiles:                    ; Last file was found
  1586.     cmp    on_disk,0            ; see if there is a files file
  1587.     jz    no_files            ; if not, just return
  1588.     cmp    num_names,0            ; see if any left in buffer
  1589.     jz    no_files
  1590.     mov    AL,num_names            ; Yes, get the number of names
  1591.     mov    BL,13                ; length of a name
  1592.     mul    BL                ; how many bytes to write
  1593.     mov    DX,offset save_buf        ; point to buffer
  1594.     mov    BX,files_handle            ; get the file handle
  1595.     mov    CX,AX                ; number of bytes to write
  1596.     mov    AH,WriteFile            ; write to the file
  1597.     int    DOS
  1598.  
  1599. ; Hmmmmm. If disk is full, un-archiver will report error. If it's just
  1600. ; a bad read/write, DOS's abort, retry, ignore will display. Don't
  1601. ; think we have to check?
  1602.  
  1603. ; All files (if any) have been found and buffered or written to disk. Save
  1604. ; the address of the buffer in case we have files in the buffer. Restore the
  1605. ; DTA.
  1606.  
  1607. no_files:
  1608.     mov    fname_ptr,offset save_buf    ;Address of scratch space
  1609.     mov    names_used,0            ; No names used yet
  1610.     ret
  1611. FindNames    endp
  1612.  
  1613. ;****************************************************************************
  1614. ; wild_card: Each time called this returns the next name in the list, if any.
  1615. ;  It 'returns' it by copying it into the end of the command line buffer
  1616. ;  after the path so it can be used immediatly. If it has no more names,
  1617. ;  it exits the program.
  1618. ; This procedure written by Jeffrey J. Nonken (and mangled by Dan)
  1619. ;****************************************************************************
  1620.     public    wild_card
  1621. wild_card    proc    near
  1622.     mov    AX,names_used            ; Get number of names returned
  1623.     cmp    AX,name_count            ; Compare to total # of names
  1624.     jb    more_names            ; If less, we still have some
  1625.  
  1626. ; We have no names left to return. See if they were on disk. If so, close up.
  1627.  
  1628.     cmp    on_disk,0            ; see if on disk
  1629.     jz    w_skip_close            ; if not, skip over the close
  1630.     mov    AH,CloseFile            ; close file command
  1631.     mov    BX,files_handle            ; get the file handle
  1632.     int    DOS
  1633.     mov    AH,DeleteFile            ; Delete file command
  1634.     mov    DX,offset filename_file        ; Name of file to delete
  1635.     int    DOS                ; Delete our scratch file
  1636. w_skip_close:
  1637.     mov    AL,elevel            ;Get last reported errorlevel
  1638.     mov    AH,ExitWithCode            ;Terminate with return code
  1639.     int    DOS                ;Exit program
  1640.  
  1641.  
  1642. ; We still have names left. Let's see if they're on disk.
  1643.  
  1644. more_names:
  1645.     cmp    on_disk,0            ; Are they stored on disk?
  1646.     jz    not_on_disk            ; If not, get from the buffer.
  1647.  
  1648. ; If we got here, the files are stored on disk. Read one name, 13 bytes, right
  1649. ; into the file spec. The name was originally null terminated, so extra junk
  1650. ; on the end won't matter.
  1651.  
  1652.     mov    AH,ReadFile            ; Read file command
  1653.     mov    BX,files_handle            ; get the file handle
  1654.     mov    DX,endpath            ;Get end address of path
  1655.     mov    CX,13                ; Read 1 filename
  1656.     int    DOS
  1657.     jnc    w_got1                ; If no carry, we got it
  1658.  
  1659. ; If we can't process the temp file, SPAZ has no filenames to work with.
  1660. ; The only safe thing to do, is exit with the errorlevel. This will leave
  1661. ; any archives intact so they can be handled later.
  1662.  
  1663.     call    err_msg                ;Report error in english
  1664.     mov    DX,offset TempErr        ;Error processing temp file
  1665.     mov    AH,OutputString            ;DOS print string function
  1666.     int    DOS                ;Display error
  1667.     mov    AH,ExitWithCode            ;Terminate SPAZ
  1668.     int    DOS                ;Tell DOS to do it
  1669.  
  1670.  
  1671. ; If we got here, there are four or fewer filenames, and they are in the
  1672. ; scratch buffer. fname_ptr points to the current filename. Just copy all
  1673. ; 13 bytes in; as before, the name was already null terminated.
  1674.  
  1675. not_on_disk:
  1676.     push    SI                ; Save the index registers
  1677.     push    DI
  1678.     mov    SI,fname_ptr            ; get the current source ptr
  1679.     mov    DI,endpath            ; Get end address of path
  1680.     mov    CX,6                ; copy 12 bytes (6 words)
  1681.     rep movsw
  1682.     movsb                    ; copy the 13th byte
  1683.     mov    fname_ptr,SI            ; save the new pointer
  1684.     pop    DI                ; restore the index registers
  1685.     pop    SI
  1686.  
  1687. ; One way or another, we copied a filename.
  1688.  
  1689. w_got1:
  1690.     inc    names_used            ; Note that we used a name
  1691.     clc                    ; Clear the carry flag
  1692.     ret
  1693. wild_card    endp
  1694.  
  1695.  
  1696. ; The following routine scans each command line option and sets various
  1697. ; flags according to options used.
  1698.  
  1699. options    proc    near
  1700.     cld                    ;Ensure forward movements
  1701.     xor    AX,AX                ;Start with argument 1
  1702. Opt0:    inc    AX                ;Bump argument number
  1703.     push    AX                ;Save argument number
  1704.     mov    BX,cmdtail            ;Point BX to command line
  1705.     call    argv                ;Get info on argument
  1706.     or    AX,AX                ;Did we find an argument?
  1707.     jnz    StillMore
  1708.     jmp    end_Opts            ;Nope, we must be done...
  1709. StillMore:
  1710.     push    AX                ;Save argument length
  1711.     mov    SI,BX                ;Address in SI
  1712.     call    upper                ;Convert to upper case
  1713.     lodsb                    ;Get first character
  1714.     cmp    AL,'/'                ;Is this an option?
  1715.     je    Opt1                ;Go get it if yes
  1716.     cmp    AL,'-'                ;Option?
  1717.     jne    arc_name            ;Get archive name
  1718. Opt1:    pop    AX                ;Get argument length back
  1719.     push    AX                ;Maintain stack balance
  1720.     cmp    AX,2                ;Check for valid size
  1721.     jne    bad_opt                ;Report bad option
  1722.     lodsb                    ;Get option ID
  1723.     cmp    AL,'D'                ;Delete flag?
  1724.     jne    Opt2                ;Next check if not
  1725.     mov    byte ptr D_Flag,true        ;Set flag to delete arc's
  1726.     jmp    short nxt_opt            ;Do next option
  1727. Opt2:    cmp    AL,'N'                ;Sort flag?
  1728.     jne    Opt3                ;Next check if not
  1729.     mov    byte ptr N_Flag,false        ;Set flag for no sort
  1730.     jmp    short nxt_opt            ;Do next option
  1731. Opt3:    cmp    AL,'A'                ;Default arc program flag?
  1732.     jne    Opt4                ;Next check if not
  1733.     mov    byte ptr A_Flag,true        ;Set flag to show default set
  1734.     jmp    short nxt_opt            ;Do next option
  1735. Opt4:    cmp    AL,'V'                ;Verbose mode desired?
  1736.     jne    Opt5                ;Next check if not
  1737.     mov    byte ptr Q_Flag,false        ;**Kludge** inverted quiet
  1738.     jmp    short nxt_opt            ;Do next option
  1739. Opt5:    cmp    AL,'F'                ;Is this a mail run?
  1740.     jne    Opt6                ;Report bad option if not
  1741.     mov    byte ptr F_Flag,true        ;Set up for mail run
  1742.     jmp    short nxt_opt            ;Do next option
  1743. Opt6:    cmp    AL,'O'                ;Overwrite mode?
  1744.     jne    Opt7                ;Make 1 more check
  1745.     mov    byte ptr O_Flag,true        ;Set overwrite mode
  1746.     jmp    short nxt_opt
  1747. Opt7:    cmp    AL,'R'                ;For Opus compatibility
  1748.     jne    bad_opt             ;Report bad option if not
  1749.     mov    byte ptr O_Flag,true        ;Set overwrite mode
  1750.     jmp    short nxt_opt
  1751. bad_opt:
  1752.     call    CheckMFlag            ;Are we expanding addresses?
  1753.     jnc    Nxt_Opt                ;It's Ok, keep going
  1754.     mov    AX,23                ;Unknow option used...
  1755.     call    err_msg                ;Report it
  1756.     jmp    syntax                ;Show syntax screen and exit
  1757.  
  1758. arc_name:
  1759.     pop    AX                ;Get length back
  1760.     push    AX                ;Maintain stack balance
  1761.     cmp    byte ptr Got_name,true        ;Do we have an archive name?
  1762.     jne    arc_name1            ;Nope, go get it
  1763.     call    parse_line            ;Yup, pass it the filenames...
  1764.     jmp    short nxt_opt            ;Continue with options
  1765.  
  1766. arc_name1:
  1767.     mov    Opt_Address,BX            ;Save address of file name
  1768.     mov    Opt_Length,AX            ;Save length of file name
  1769.     mov    byte ptr Got_name,true        ;Set flag to show we got it!
  1770.  
  1771. nxt_opt:
  1772.     pop    AX                ;Remove argument length
  1773.     pop    AX                ;Get arg number to work on
  1774.     jmp    Opt0                ;Continue...
  1775.  
  1776. end_Opts:
  1777.     add    SP,2                ;Clean off stack junk
  1778.     cmp    byte ptr Got_name,true        ;Did we get a filename?
  1779.     jne    bad_line            ;Report error if not
  1780.     cmp    F_Flag,true            ;Is this a mail run?
  1781.     jne    RestoreArg            ;Go if not
  1782.     mov    byte ptr D_Flag,true        ;Set auto delete
  1783.     mov    byte ptr N_Flag,true        ;Force an archive sort
  1784.     mov    byte ptr O_Flag,true        ;Force overwrite mode
  1785. RestoreArg:
  1786.     mov    AX,Opt_Length            ;Get length of argument
  1787.     mov    BX,Opt_Address            ;Get address of argument
  1788.     ret                    ;And we are outa' here..
  1789.  
  1790. ;If the program falls through to here, all arguments were examined and
  1791. ;an archive name was NOT found. Report an error, show the syntax screen
  1792. ;and quit. What else can we do?
  1793.  
  1794. bad_line:
  1795.     mov    AX,24
  1796.     call    err_msg
  1797.     jmp    syntax
  1798. options    endp
  1799.  
  1800.  
  1801. CheckMFlag    proc    near
  1802.  
  1803.     lodsb                    ;Get next character
  1804.     cmp    AL,'M'                ;Is this the M flag?
  1805.     jne    NotTheMFlag            ;Exit if no
  1806.     call    DecimalIn            ;Get net number
  1807.     mov    word ptr OurNet,DX        ;Save it
  1808.     call    DecimalIn            ;Get node number
  1809.     mov    word ptr OurNode,DX        ;Save it
  1810.     mov    M_Flag,true            ;Set our flag
  1811.     clc                    ;Show we processed it
  1812.     ret                    ;And exit
  1813. NotTheMFlag:
  1814.     stc                    ;Oops, a boo-boo...
  1815.     ret                    ;Back to caller
  1816.  
  1817. CheckMFlag    endp
  1818.  
  1819.  
  1820. ; This routine displays the current settings of the command line
  1821. ; parameters. i.e. will sort, will not delete etc...
  1822.  
  1823. show_opt    proc    near
  1824.     push    AX
  1825.     push    BX
  1826.  
  1827.     cmp    byte ptr Q_Flag,true        ;Quiet mode?
  1828.     jne    NotQuietMode
  1829.     jmp    show_x                ;Exit if yes
  1830.  
  1831. NotQuietMode:
  1832.     cld                    ;Ensure forward movements
  1833.     mov    SI,offset will            ;Point to will message
  1834.     cmp    byte ptr A_Flag,true        ;Use Arce?
  1835.     je    show1
  1836.     mov    SI,offset wont
  1837. show1:    call    ShowIt
  1838.     mov    SI,offset info1
  1839.     call    ShowIt
  1840.  
  1841.     mov    SI,offset will
  1842.     cmp    byte ptr D_Flag,true        ;Delete archives?
  1843.     je    show2
  1844.     mov    SI,offset wont
  1845. show2:    call    ShowIt
  1846.     mov    SI,offset info2
  1847.     call    ShowIt
  1848.  
  1849.     mov    SI,offset will
  1850.     cmp    M_Flag,true            ;Expand net address?
  1851.     je    show3
  1852.     mov    SI,offset wont
  1853. show3:    call    ShowIt
  1854.     mov    SI,offset info5
  1855.     call    ShowIt
  1856.  
  1857.     mov    SI,offset will
  1858.     cmp    F_Flag,true            ;A mail run?
  1859.     je    show4
  1860.     mov    SI,offset wont
  1861. show4:    call    ShowIt
  1862.     mov    SI,offset info6
  1863.     call    ShowIt
  1864.  
  1865.     mov    SI,offset will
  1866.     cmp    byte ptr O_Flag,true        ;Force overwrite mode?
  1867.     je    show5
  1868.     mov    SI,offset wont
  1869. show5:    call    ShowIt
  1870.     mov    SI,offset info7
  1871.     call    ShowIt
  1872.  
  1873.     mov    SI,offset will
  1874.     cmp    byte ptr N_Flag,true        ;Sort archive?
  1875.     je    show6
  1876.     mov    SI,offset wont
  1877. show6:    call    ShowIt
  1878.     mov    SI,offset info3
  1879.     call    ShowIt
  1880.  
  1881. show_x:    pop    BX
  1882.     pop    AX
  1883.     ret
  1884. show_opt    endp
  1885.  
  1886.  
  1887. ; This procedure converts an ASCII number to it's binary form. The
  1888. ; routine will exit when the first non-ascii-number is reached. The
  1889. ; binary value is returned in DX.
  1890.  
  1891. DecimalIn    proc    near
  1892.  
  1893.     xor    DX,DX                ;Initialize variable
  1894. DecimalLoop:
  1895.     lodsb                    ;Get first character
  1896.     sub    AL,30h                ;Subtract ASCII base
  1897.     jl    DecimalExit            ;If too low, we're finished
  1898.     cmp    AL,9
  1899.     jg    DecimalExit            ;If too high, we're finished
  1900.     cbw                    ;Convert to word value
  1901.     push    AX                ;Save digit
  1902.     mov    AX,DX
  1903.     mov    CX,10                ;Working with base 10
  1904.     mul    CX                ; 10 * digit
  1905.     mov    DX,AX                ;Result in DX
  1906.     pop    AX                ;Get number back
  1907.     add    DX,AX                ;Add number in
  1908.     jmp    short DecimalLoop        ;Get next digit
  1909. DecimalExit:
  1910.     ret                    ;Back to main section
  1911.  
  1912. DecimalIn    endp
  1913.  
  1914.  
  1915. ; This routine parses filenames from the command line that must be passed
  1916. ; to the unarchive program.
  1917.  
  1918. parse_line    proc    near
  1919.     cld                    ;Go in the right direction!
  1920.     mov    Parsed,true            ;Show names were parsed
  1921.     mov    CX,word ptr Names_Count        ;Get current character count
  1922.     push    AX                ;Save argument length
  1923.     add    AX,CX                ;AX = new length total
  1924.     mov    SI,BX                ;Argument address to source
  1925.     mov    DI,offset Extract_Names        ;DI = buffer address
  1926.     add    DI,CX                ;Adjust to current position
  1927.     mov    byte ptr [DI],blank        ;Add in a space
  1928.     inc    DI                ;Adjust pointer
  1929.     inc    AX                ;Add 1 to total length
  1930.     mov    word ptr Names_Count,AX        ;Save new total length
  1931.     pop    CX                ;Get argument length in CX
  1932.     rep    movsb                ;Move extract name into buffer
  1933.     mov    byte ptr [DI],0            ;End it with a null
  1934.     ret
  1935. parse_line    endp
  1936.  
  1937.  
  1938. DisplayNode    proc    near
  1939.  
  1940.     cmp    M_Flag,true            ;Should we do this?
  1941.     jne    ExitDisplayNode            ;Exit if not
  1942.  
  1943.     mov    SI,endpath            ;Point to bundle name
  1944.     call    GetFromAddress            ;Decode the Address
  1945.     mov    DI,offset BuildNet        ;Where to store it
  1946.     mov    AX,word ptr FromNet        ;Get the Senders net
  1947.     mov    DX,word ptr OurNet        ;Get our own net
  1948.     add    AX,DX                ;Figure out the difference
  1949.     xor    DX,DX                ;Get ready for conversion
  1950.     call    DecimalOut            ;Convert to ASCII
  1951.     call    InsertAddress            ;Add Net number to string
  1952.     mov    AL,'/'                ;Address delimiter
  1953.     stosb                    ;Stuff it in
  1954.     mov    AX,word ptr FromNode        ;Get the Senders node
  1955.     mov    DX,word ptr OurNode        ;Get our node address
  1956.     add    AX,DX                ;Figure out the difference
  1957.     xor    DX,DX                ;Get ready for conversion
  1958.     call    DecimalOut            ;Convert to ASCII
  1959.     call    InsertAddress            ;Add node number to string
  1960.     mov    byte ptr [DI],0            ;Make it ASCIIZ
  1961. ExitDisplayNode:
  1962.     ret                    ;Back to main
  1963.  
  1964. DisplayNode    endp
  1965.  
  1966.  
  1967. InsertAddress    proc    near
  1968.  
  1969.     mov    SI,offset DecBuf        ;Point to ASCII buffer
  1970. Insert1:
  1971.     lodsb                    ;Get a byte
  1972.     cmp    AL,blank            ;Is it ASCII space?
  1973.     je    Insert1                ;Loop if yes
  1974. Insert2:
  1975.     stosb                    ;Not 0, we keep it...
  1976.     lodsb                    ;And get another
  1977.     or    AL,AL                ;Check for end
  1978.     jnz    Insert2                ;Loop till finished
  1979.     ret                    ;Back to caller
  1980.  
  1981. InsertAddress    endp
  1982.  
  1983.  
  1984. GetFromAddress    proc    near
  1985.  
  1986.     call    GetNet                ;Get the net bundle is from
  1987.     mov    word ptr FromNet,DX        ;And save it
  1988.     call    GetNet                ;Get the node number
  1989.     mov    word ptr FromNode,DX        ;And save it
  1990.     ret                    ;That's it!
  1991. GetNet:
  1992.     xor    DX,DX                ;Start with 0
  1993.     mov    CX,4                ;Counter for Hex number
  1994. Net1:    lodsb                    ;Grab a byte
  1995.     sub    AL,30h                ;Mask off the ASCII
  1996.     jl    Net3                ;Too low, exit
  1997.     cmp    AL,9                ;0 to 9?
  1998.     jle    Net2                ;If yes, no adjustment
  1999.     and    AL,5fh                ;Mask off the casing
  2000.     sub    AL,7                ;Adjust for A-F
  2001.     jl    Net3                ;Quit if too low
  2002.     cmp    AL,15                ;Higher than F?
  2003.     jg    Net3                ;Quit if too high
  2004. Net2:    push    CX                ;Save character counter
  2005.     cbw                    ;Sign extend our number
  2006.     mov    CL,4                ;4 bits per hex character
  2007.     sal    DX,CL                ;Shift over previous value
  2008.     add    DX,AX                ;And add in the new
  2009.     pop    CX                ;Restore character counter
  2010.     loop    Net1                ;Do 4 characters
  2011. Net3:    ret                    ;And then exit
  2012.  
  2013. GetFromAddress    endp
  2014.  
  2015.  
  2016. BuildNet    equ    $            ;Buffer for Net/Node
  2017. FromNet        equ    BuildNet + 12        ;Sending Net
  2018. FromNode    equ    FromNet + 2        ;Sending Node
  2019. OurNet        equ    FromNode + 2        ;Our Net
  2020. OurNode        equ    OurNet + 2        ;Our Node
  2021. cpy_buf        equ    OurNode + 2        ;Storage for copy buffer
  2022. hdr_buf        equ    cpy_buf + bsize        ;Buffer to hold headers
  2023. cmd1    equ    hdr_buf + entries * arc_len    ;Buffer for wildcard filenames
  2024. new        equ    cmd1 + 80        ;Buffer for Arc path search
  2025. saved        equ    new + 80        ;Buffer for Arc exec
  2026. decbuf        equ    saved + 192        ;Buffer for decimal conversions
  2027. dta_buf        equ    decbuf + 8        ;Disk Transfer Area
  2028. Def_Arc        equ    dta_buf + 43        ;Default Archive Name
  2029. Fcb1        equ    Def_Arc + 13        ;File Control Block 1
  2030. Fcb2        equ    Fcb1 + 37        ;File control Block 2
  2031. Cmd_Cnt        equ    Fcb2 + 37        ;Command Line Char Counter
  2032. ExtractOptions    equ    Cmd_Cnt + 1        ;Options to pass to Un-Archer
  2033. Pakfile     equ    ExtractOptions + 9    ;Filenames to pass to Un-Archer
  2034. Extract_Names    equ    Pakfile + 160        ;Buffer for names to extract
  2035. Names_Count    equ    Extract_Names + 128    ;Count for names to extract
  2036. tempspec    equ    Names_Count + 2        ;Scratch for temp filespec .jjn
  2037. save_buf    equ    tempspec + 80        ; Filename buffer          .jjn
  2038. stk    equ    save_buf + (13 * NamesFound)    ;Stack Area                .jjn
  2039. bottom        equ    stk + 200        ;End of code and data
  2040.  
  2041. cseg    ends
  2042.  
  2043.     end    entry
  2044.